package msgo

import (
	"fmt"
	"gitee.com/MrDaiM/msgo/config"
	"gitee.com/MrDaiM/msgo/gateway"
	msgLog "gitee.com/MrDaiM/msgo/log"
	"gitee.com/MrDaiM/msgo/register"
	"gitee.com/MrDaiM/msgo/render"
	"html/template"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"sync"
)

const ANY = "ANY"

type HandlerFunc func(ctx *Context)

type MiddlewareFunc func(handlerFunc HandlerFunc) HandlerFunc

type router struct {
	routerGroups []*routerGroup
	engine       *Engine
}

func (r *router) Group(name string) *routerGroup {
	g := &routerGroup{
		name:               name,
		handleFuncMap:      make(map[string]map[string]HandlerFunc),
		handlerMethodMap:   make(map[string][]string),
		middlewaresFuncMap: make(map[string]map[string][]MiddlewareFunc),
		treeNode:           &treeNode{name: "/", children: make([]*treeNode, 0)},
	}
	// 一旦创建 group 那么就设置好中间件
	g.Use(r.engine.middles...) // 提供 默认的 中间件
	r.routerGroups = append(r.routerGroups, g)
	return g
}

// ErrorHandler int 返回的状态 any 返回的错误信息
type ErrorHandler func(err error) (int, any)

type Engine struct {
	router
	funcMap        template.FuncMap  // 存放自定义函数
	HTMLRender     render.HTMLRender // 存放模版
	pool           sync.Pool         // 防止频繁创建context
	Logger         *msgLog.Logger
	middles        []MiddlewareFunc
	errorHandler   ErrorHandler
	OpenGateWay    bool
	gatewayConfigs []gateway.GWConfig

	gatewayTreeNode  *gateway.TreeNode
	gatewayConfigMap map[string]gateway.GWConfig
	RegisterType     string
	RegisterOption   register.Option
	RegisterCli      register.MsRegister
}

func New() *Engine {

	engine := &Engine{
		router:           router{},
		funcMap:          nil,
		HTMLRender:       render.HTMLRender{},
		gatewayTreeNode:  &gateway.TreeNode{Name: "/", Children: make([]*gateway.TreeNode, 0)},
		gatewayConfigMap: make(map[string]gateway.GWConfig),
	}
	engine.pool.New = func() any {
		return engine.allocateContext()
	}

	return engine

}
func Default() *Engine {
	engine := New()
	engine.Logger = msgLog.Default()
	logPath, ok := config.Conf.Log["path"]
	if ok {
		engine.Logger.SetLogPath(logPath.(string))
	}

	engine.Use(Logging, Recovery) // 暂时存一下，传递给group 进行中间件设置 将中间件绑定到路由引擎上， 提前设置好固定的中间件
	engine.router.engine = engine
	return engine
}

func (e *Engine) allocateContext() any {
	return &Context{engine: e}
}

func (e *Engine) SetGatewayConfig(configs []gateway.GWConfig) {
	e.gatewayConfigs = configs
	// 把这个路径存储起来 访问的时候去匹配这里面的路由， 如果匹配，就拿出来相应的匹配结果
	for _, v := range e.gatewayConfigs {
		e.gatewayTreeNode.Put(v.Path, v.Name)
		e.gatewayConfigMap[v.Name] = v
	}

	fmt.Println(e)
}

func (e *Engine) SetFuncMap(funcMap template.FuncMap) {
	e.funcMap = funcMap
}

// LoadTemplate 加载所有模板
func (e *Engine) LoadTemplate(pattern string) {
	t := template.Must(template.New("").Funcs(e.funcMap).ParseGlob(pattern))
	e.SetHtmlTemplate(t)
}

func (e *Engine) LoadTemplateConf() {
	pattern, ok := config.Conf.Template["pattern"]
	if ok {
		t := template.Must(template.New("").Funcs(e.funcMap).ParseGlob(pattern.(string)))
		e.SetHtmlTemplate(t)
	}

}

// SetHtmlTemplate 提供自定义的设置方法
func (e *Engine) SetHtmlTemplate(t *template.Template) {
	e.HTMLRender = render.HTMLRender{Template: t}
}

func (e *Engine) Handler() http.Handler {
	return e
}

func (e *Engine) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
	// 获取后重新赋值
	ctx := e.pool.Get().(*Context)
	ctx.W = writer
	ctx.R = request
	ctx.Logger = e.Logger
	e.httpRequestHandle(ctx, writer, request)
	// 放回缓存中区
	e.pool.Put(ctx)
}

func (e *Engine) httpRequestHandle(ctx *Context, writer http.ResponseWriter, request *http.Request) {

	if e.OpenGateWay {
		// 请i去过来, 具体转发到哪里
		path := request.URL.Path
		node := e.gatewayTreeNode.Get(path)
		if node == nil {
			ctx.W.WriteHeader(http.StatusNotFound)
			_, _ = fmt.Fprintln(ctx.W, ctx.R.RequestURI+" not found")
			return
		}

		// 获取网关的配置
		gwConfig := e.gatewayConfigMap[node.GwName]
		// 调用外部提供的方法，设置请求头（这样就可以接受外部更改请求头）
		gwConfig.Header(ctx.R)

		// 目标请求路径（url 解析）
		addr, err := e.RegisterCli.GetValue(gwConfig.ServiceName)
		if err != nil {
			ctx.W.WriteHeader(http.StatusInternalServerError)
			_, _ = fmt.Fprintln(ctx.W, err.Error())
			return
		}
		//target, err := url.Parse(fmt.Sprintf("http://%s:%d%s", gwConfig.Host, gwConfig.Port, path))
		target, err := url.Parse(fmt.Sprintf("http://%s%s", addr, path))
		if err != nil {
			ctx.W.WriteHeader(http.StatusInternalServerError)
			_, _ = fmt.Fprintln(ctx.W, err.Error())
			return
		}

		// director, response, handler 可以提供出去让外部去拓展
		// 网关的处理逻辑
		director := func(req *http.Request) {
			// 将原因有请求进行替换
			req.Host = request.Host
			req.URL.Host = target.Host
			req.URL.Path = target.Path
			req.URL.Scheme = target.Scheme
			if _, ok := req.Header["User-Agent"]; !ok { // 如果没有值可以空值，否则无法识别
				req.Header.Set("User-Agent", "")
			}
		}
		response := func(response *http.Response) error {
			log.Println("响应修改")
			return nil
		}

		handler := func(writer http.ResponseWriter, request *http.Request, err error) {
			log.Println("错误处理")
		}

		proxy := httputil.ReverseProxy{Director: director, ModifyResponse: response, ErrorHandler: handler}

		// 代理
		proxy.ServeHTTP(writer, request)

		return

	}

	method := request.Method
	for _, group := range e.routerGroups {
		log.Println(request.URL.Path)   // 不携带参数 /user/string
		log.Println(request.RequestURI) // 携带参数 /user/string?id=1
		routerName := SubStringLast(request.URL.Path, "/"+group.name)
		// get/1
		node := group.treeNode.Get(routerName)

		if node == nil || !node.isEnd {
			writer.WriteHeader(http.StatusNotFound)
			fmt.Fprintln(writer, request.RequestURI+" not found")
			return
		}

		if node != nil {
			// 路由匹配上了
			//ctx := &Context{
			//	W:      writer,
			//	R:      request,
			//	engine: e,
			//}
			// 检测是否有ANY的请求方式
			handle, ok := group.handleFuncMap[node.routerName][ANY]
			if ok {
				//handle(ctx)
				group.methodHandle(node.routerName, method, handle, ctx)
				return
			}

			// 其他的请求方式
			handle, ok = group.handleFuncMap[node.routerName][method]
			if ok {
				//handle(ctx)
				group.methodHandle(node.routerName, method, handle, ctx)
				return
			}
			writer.WriteHeader(http.StatusMethodNotAllowed)
			_, _ = fmt.Fprintf(writer, "%s %s not allowed \n", request.RequestURI, method)
			return
		}
	}
	writer.WriteHeader(http.StatusNotFound)
	_, _ = fmt.Fprintf(writer, "%s  not found \n", request.RequestURI)
}

func (e *Engine) RunTLS(addr, cetFile, keyFile string) {
	err := http.ListenAndServeTLS(addr, cetFile, keyFile, e.Handler())
	if err != nil {
		log.Fatal(err)
	}
}

func (e *Engine) Run(addr string) {

	if e.RegisterType == "nacos" {
		nacosRegister := register.MsNacosRegister{}
		err := nacosRegister.CreateCli(e.RegisterOption)
		if err != nil {
			panic(err)
		}
		e.RegisterCli = &nacosRegister
	}
	if e.RegisterType == "etcd" {
		etcdRegister := register.MsETCDRegister{}
		err := etcdRegister.CreateCli(e.RegisterOption)
		if err != nil {
			panic(err)
		}
		e.RegisterCli = &etcdRegister
	}

	http.Handle("/", e) // Handle 需要实现协议的方法 ServeHTTP
	err := http.ListenAndServe(addr, nil)
	if err != nil {
		log.Fatal(err)
	}
}

func (e *Engine) Use(middles ...MiddlewareFunc) {
	e.middles = append(e.middles, middles...)
}

func (e *Engine) RegisterErrorHandler(handler ErrorHandler) {
	e.errorHandler = handler
}

type routerGroup struct {
	name               string
	handleFuncMap      map[string]map[string]HandlerFunc      // key:请求路径 value: 支持同一个路径不同请求方式
	middlewaresFuncMap map[string]map[string][]MiddlewareFunc // 函数级中间件 key:string(请求路径) value:map[string][]MiddlewareFunc 请求方法:函数结构
	handlerMethodMap   map[string][]string                    // Key:GET、POST、PUT value:["path","path"]
	treeNode           *treeNode
	middlewareMap      map[string]map[string][]MiddlewareFunc
	middlewares        []MiddlewareFunc
}

func (r *routerGroup) Use(middlewares ...MiddlewareFunc) {
	r.middlewares = append(r.middlewares, middlewares...)
}

func (r *routerGroup) methodHandle(name string, method string, handlerFunc HandlerFunc, ctx *Context) {
	// 组通用中间件
	if r.middlewares != nil {
		for _, middleFunc := range r.middlewares {
			handlerFunc = middleFunc(handlerFunc)
		}
	}

	// 组路由级别中间件 方法级
	middlewareFuncs := r.middlewaresFuncMap[name][method]
	if middlewareFuncs != nil {
		for _, middlewareFunc := range middlewareFuncs {
			handlerFunc = middlewareFunc(handlerFunc)
		}
	}

	// 正常执行逻辑
	handlerFunc(ctx)

}

func (r *routerGroup) handle(name string, method string, handlerFunc HandlerFunc, middlewareFunc ...MiddlewareFunc) {
	_, ok := r.handleFuncMap[name]
	if !ok {
		r.handleFuncMap[name] = make(map[string]HandlerFunc)
		// 添加函数级别的中间件
		r.middlewaresFuncMap[name] = make(map[string][]MiddlewareFunc)
	}

	_, ok = r.handleFuncMap[name][method]
	if ok {
		panic("有重复的路由")
	}

	// name 是请求路径， method 是请求方式， 可以有不多的请求方式
	r.handleFuncMap[name][method] = handlerFunc
	// 添加方法级的中间件
	r.middlewaresFuncMap[name][method] = append(r.middlewaresFuncMap[name][method], middlewareFunc...)
	// 请求方法对用的完整路径 ??? 似乎没有用处了
	r.handlerMethodMap[method] = append(r.handlerMethodMap[method], name)

	// 添加节点
	r.treeNode.Put(name)
}

func (r *routerGroup) Handle(name string, method string, handlerFunc HandlerFunc, middlewareFunc ...MiddlewareFunc) {
	// method 有效性校验
	r.handle(name, method, handlerFunc, middlewareFunc...)
}

func (r *routerGroup) Any(name string, handlerFunc HandlerFunc, middlewareFunc ...MiddlewareFunc) {
	r.handle(name, ANY, handlerFunc, middlewareFunc...)
}

func (r *routerGroup) Get(name string, handlerFunc HandlerFunc, middlewareFunc ...MiddlewareFunc) {
	r.handle(name, http.MethodGet, handlerFunc, middlewareFunc...)
}

func (r *routerGroup) Post(name string, handlerFunc HandlerFunc, middlewareFunc ...MiddlewareFunc) {
	r.handle(name, http.MethodPost, handlerFunc, middlewareFunc...)
}
func (r *routerGroup) Delete(name string, handlerFunc HandlerFunc, middlewareFunc ...MiddlewareFunc) {
	r.handle(name, http.MethodDelete, handlerFunc, middlewareFunc...)
}
func (r *routerGroup) Put(name string, handlerFunc HandlerFunc, middlewareFunc ...MiddlewareFunc) {
	r.handle(name, http.MethodPut, handlerFunc, middlewareFunc...)
}
func (r *routerGroup) Patch(name string, handlerFunc HandlerFunc, middlewareFunc ...MiddlewareFunc) {
	r.handle(name, http.MethodPatch, handlerFunc, middlewareFunc...)
}
func (r *routerGroup) Options(name string, handlerFunc HandlerFunc, middlewareFunc ...MiddlewareFunc) {
	r.handle(name, http.MethodOptions, handlerFunc, middlewareFunc...)
}
func (r *routerGroup) Head(name string, handlerFunc HandlerFunc, middlewareFunc ...MiddlewareFunc) {
	r.handle(name, http.MethodHead, handlerFunc, middlewareFunc...)
}
